//
// Created by hsby on 2021/4/19.
//

#include <iostream>
#include <vector>
#include <yaml-cpp/yaml.h>

#include "hsby.h"

const std::string rootPath("/mnt/hgfs/share/Project/scaffold");

hsby::ConfigVar<float>::Ptr g_int_value_config =
        hsby::Config::Lookup("system.port",(float)100, "server.port");

hsby::ConfigVar<float>::Ptr g_float_value_config =
        hsby::Config::Lookup("system.value", (float)1.9999, "server.port");

hsby::ConfigVar<std::vector<int>>::Ptr g_int_vec_value_config =
        hsby::Config::Lookup("system.int_vec", std::vector<int>{1, 2}, "system.int_vec");

hsby::ConfigVar<std::list<int>>::Ptr g_int_list_value_config =
        hsby::Config::Lookup("system.int_list", std::list<int>{1, 2}, "system.int_list");

hsby::ConfigVar<std::set<int>>::Ptr g_int_set_value_config =
        hsby::Config::Lookup("system.int_set", std::set<int>{1, 2}, "system.int_set");

hsby::ConfigVar<std::unordered_set<int>>::Ptr g_int_unordered_set_value_config =
        hsby::Config::Lookup("system.int_unordered_set", std::unordered_set<int>{1, 2}, "system.int_unordered_set");

hsby::ConfigVar<std::map<std::string, int>>::Ptr g_str_int_map_value_config =
        hsby::Config::Lookup("system.str_map", std::map<std::string, int>{{"key1", 11}, {"key2", 22}}, "system.str_map");

hsby::ConfigVar<std::unordered_map<std::string, int>>::Ptr g_str_int_uo_map_value_config =
        hsby::Config::Lookup("system.str_unordered_map", std::unordered_map<std::string, int>{{"key1", 11}, {"key2", 22}}, "system.str_unordered_map");

void print_yaml(const YAML::Node& node, int level){
    if (node.IsScalar()){
        HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << std::string(level*4, ' ') << node.Scalar() << " - " << node.Type() << " - " << level;
    }else if (node.IsNull()){
        HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << std::string(level*4, ' ')  <<   "NULL" << " - " << node.Type() << " - " << level;
    }else if (node.IsMap()){
        for(auto it = node.begin();
            it != node.end(); ++it ){
            HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << std::string(level*4, ' ')  << it->first << " - " << it->first.Type() << " - " << level;
            print_yaml(it->second, level+1);
        }
    }else if (node.IsSequence()){
        for (size_t i = 0; i < node.size(); ++i) {
            HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) <<std::string(level*4, ' ') << i << " - " << node[i].Type() << " - " << level;
            print_yaml(node[i], level+1);
        }
    }
}

void test_yaml(){
    YAML::Node root = YAML::LoadFile(rootPath+"/bin/conf/log.yml");
    print_yaml(root, 0);
}

void test_config(){
    HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << g_int_value_config->ToString();
    HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << g_float_value_config->ToString();

    YAML::Node root = YAML::LoadFile("/bin/conf/log.yml");
    hsby::Config::LoadFromYaml(root);

    HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << g_int_value_config->ToString();
    HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << g_float_value_config->ToString();
}

#define P_SEQ_VAR(g_var, name, order)\
    {                                \
        auto& v = g_var->GetValue();      \
        for (auto& i : v) {         \
            HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << " "#order" "#name" : " << i;\
        }                            \
        HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << " "#order" "#name" yaml : " << g_var->ToString();\
    }

#define P_MAP_VAR(g_var, name, order)\
    {                                \
        auto& v = g_var->GetValue();      \
        for (auto& i : v) {         \
            HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << " "#order" "#name" : " << "[" << i.first << ":" << i.second << "]";\
        }                            \
        HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << " "#order" "#name" yaml : " << g_var->ToString();\
    }
void test_config_seq(){

    P_SEQ_VAR(g_int_vec_value_config, system.int_vec, before);
    P_SEQ_VAR(g_int_list_value_config, system.int_list, before);
    P_SEQ_VAR(g_int_set_value_config, system.int_set, before);
    P_SEQ_VAR(g_int_unordered_set_value_config, system.int_unordered_set, before);
    P_MAP_VAR(g_str_int_map_value_config, system.str_map,before);
    P_MAP_VAR(g_str_int_uo_map_value_config, system.str_unordered_map,before);

    YAML::Node root = YAML::LoadFile(rootPath+"/bin/conf/log.yml");
    hsby::Config::LoadFromYaml(root);

    P_SEQ_VAR(g_int_vec_value_config, system.int_vec, after);
    P_SEQ_VAR(g_int_list_value_config, system.int_list, after);
    P_SEQ_VAR(g_int_set_value_config, system.int_set, before);
    P_SEQ_VAR(g_int_unordered_set_value_config, system.int_unordered_set, after);
    P_MAP_VAR(g_str_int_map_value_config, system.str_map, after);
    P_MAP_VAR(g_str_int_uo_map_value_config, system.str_unordered_map, after);
}

class Person{
public:
    std::string m_name = "";
    int         m_age = 0;
    bool        m_sex = 0;
    std::string toString() const {
        std::stringstream ss;
        ss  << "Person[name=" << m_name
            << ", age=" << m_age
            << ", sex=" << m_sex
            << "]";
        return ss.str();
    }

    bool operator== (const Person& oth) const {
        return m_name == oth.m_name 
            && m_age == oth.m_age
            && m_sex == oth.m_sex;
    }
};

namespace hsby{

/*
 * @hsby 配置支持Person string-->Person
 */
template<>
class LexicalCast<std::string, Person>{
public:
    Person operator()(std::string yml){
        YAML::Node node = YAML::Load(yml);
        Person ps;
        ps.m_name = node["name"].as<std::string>();
        ps.m_age = node["age"].as<int>();
        ps.m_sex = node["sex"].as<bool>();
        return ps;
    }
};

/*
 * @hsby 配置支持Person Person-->string
 */
template<>
class LexicalCast<Person, std::string>{
public:
     std::string operator()(Person p){
        YAML::Node node;
        node[p.m_name] = p.m_name;
        node[p.m_age] = p.m_age;
        node[p.m_sex] = p.m_sex;
        std::stringstream ss;
        ss << node;
        return ss.str();
    }
};

} // namespace hsby

/*
 * @hsby 测试Person
 */
hsby::ConfigVar<Person>::Ptr g_person =
    hsby::Config::Lookup("class.person", Person(), "class.person");

hsby::ConfigVar<std::map<std::string, Person>>::Ptr g_str_person_mp =
        hsby::Config::Lookup("class.str_person_mp", std::map<std::string, Person>(), "class.g_str_person_mp");

hsby::ConfigVar<std::map<std::string, std::vector<Person>>>::Ptr g_str_person_vec_mp =
        hsby::Config::Lookup("class.str_person_vec_mp", std::map<std::string, std::vector<Person> >(), "class.g_str_person_vec_mp");


#define P_STR_MP_CLASS(g_var, order)                            \
    for(auto& p : g_var->GetValue()){                           \
        HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << " "#order" " <<  p.first << " : " << p.second.toString();\
    }

#define P_STR_VEC_MP_CLASS(g_var, order)                            \
    for(auto& ps : g_var->GetValue()){                           \
        HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << ps.first << " : " ;   \
        for(auto& p : ps.second){                               \
            HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << " "#order" " << "    " <<  p.toString();   \
        }                                                       \
    }

void test_config_class(){
    g_person->AddListener([](const Person oldp, const Person newp){
            HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << oldp.toString() << " --> " << newp.toString();
        });

    HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << " before " << g_person->GetValue().toString();
    P_STR_MP_CLASS(g_str_person_mp, before);
    P_STR_VEC_MP_CLASS(g_str_person_vec_mp, before);

    YAML::Node root = YAML::LoadFile(rootPath+"/bin/conf/test.yml");
    hsby::Config::LoadFromYaml(root);

    HSBY_LOG_DEBUG(HSBY_LOG_ROOT()) << " after " << g_person->GetValue().toString();
    P_STR_MP_CLASS(g_str_person_mp, after);
    P_STR_VEC_MP_CLASS(g_str_person_vec_mp, after);
}

void test_config_logs(){
    HSBY_LOG_DEBUG(hsby::LoggerManagerSgt::Instance().getLogger("system")) << "before load configFile" ;

    std::cout << hsby::LoggerManagerSgt::Instance().toYaml() << std::endl;
    YAML::Node root = YAML::LoadFile(rootPath+"/bin/conf/log.yml");
    hsby::Config::LoadFromYaml(root);
    //HSBY_LOG_SYSTEM_DEBUG << root << std::endl;
    std::cout << hsby::LoggerManagerSgt::Instance().toYaml() << std::endl;

    HSBY_LOG_DEBUG(hsby::LoggerManagerSgt::Instance().getLogger("system")) << "after load configFile" ;
}


int main(){
    test_config_logs();
    return 0;
}
